8051汇编指令集
51 单片机中的汇编语言,最长指令占 3 字节
标号:\quad 操作码\quad操作数\quad;注释
助记符
// 助记
Rn R0~R7
Ri R0~R1
#data 8位立即数
#data16 16位立即数
addr16 16位地址,用于64K范围内寻址
addr11 11位地址,用于2K范围内寻址
direct 8位直接地址
Rel 带符号的8位偏移量 relative_address
bit 位寻址区的直接寻址位
一、数据传送
graph LR 数据传送--> 内部数据传送 & 内部与外部RAM & 内部与外部ROM
1.内部数据传送
MOV destination,source
destination:
A
, Rn
, direct1
,@Ri
source:
A
, Rn
, direct2
, @Ri
, # data
MOV DPTR,#data16
传送 16 位的数据给 DPTR
2.外部数据传送
片内与片外 RAM
MOVX A,@DPTR/@Ri
MOVX @DPTR/@Ri,A
用来访问外部数据存储器(External Data Memory,通常是指扩展 RAM)
通过间接寻址方式指定外部 RAM 的一个字节单元地址, 寄存器 A 数据交换
MOV DPTR,#1000H
MOVX A,@DPTR
MOVC 程序储存器
3.字节交换
XCH A,direct/Rn/@Ri
用于将累加器A中的值与另一个寄存器或内存位置中的值进行交换
XCHD A,@Ri
Exchange Decimal
低半字节交换,只交换低 4 位
SWAP A
累加器 A 高 4 位和低 4 位交换
4.查表
MOVC A,@A+PC
更常使用:
MOVC A,@A+DPTR
Move Code
变址寻址
@
表示间接寻址,A
是累加器寄存器,DPTR
是数据指针寄存器。这条指令将累加器A的值和数据指针DPTR的值相加,然后以这个和作为地址,从程序存储器中取出一个字节的数据,并将这个数据移动到累加器A中
- 这里的
@A
并非是指累加器 A 中的内容,而是指累加器 A 的内容作为一个 8 位偏移量。 - CPU 会首先将累加器 A 的内容与 DPTR 的内容进行逻辑拼接(高位扩展 A 至 16 位并与 DPTR 合并),形成一个完整的 16 位地址。
- CPU 随后会根据这个拼接后形成的地址从程序存储器中读取一个字节数据。
- 最后,这个从程序存储空间读出的字节数据会被存入累加器 A。
此指令常常用于执行查表操作,比如当程序需要快速查找预先存放在程序存储器中的一张表格时,通过设置 DPTR 指向表格的首地址,然后利用 A 寄存器作为索引偏移量来快速获取表格中的特定数据项。
由于 C51 单片机的程序存储器可以被映射为数据空间的一部分,因此可以直接从中读取数据,这对于诸如字符发生器表、函数表等应用场景非常实用。
5.堆栈操作
堆栈原则:后进先出 LIFO
PUSH direct
入栈
将直接地址指定的内存位置中的值压入栈顶
POP direct
出栈
从栈顶取出数据,并将其放入直接地址指定的内存位置
PUSH 33H //将33H中的值压入栈顶,假设为1
PUSH 34H //将34H中的值压入栈顶,假设为2
POP 36H //将栈顶的值取出到36H,值为2
POP 35H //将栈顶的值取出到35H,值为1
二、算数运算
source:
Rn
direct
@Ri
# data
1.加减法
ADD A,source
不带进位的加法操作
ADDC A,source
Add with Carry
带进位的加法操作
A=A+source+CY
SUBB A,source
Subtract with Borrow
带借位的减法操作
A=A-source-CY
10-6 无借位,CY=0
4-4 有借位,CY=1 可以借助此判断数值大小
2.BCD 调整码
DA A
Decimal Adjust Accumulator
BCD 调整码,跟在 ADD、ADDC 加法指令之后
用于将二进制编码的十进制数调整为正确的十进制表示形式
MOV A,32H
ADD A,23H
DA A
MOV 42H,A
BCD 码的调整
假设有十进制计算:
18+16=34 对应结果的 BCD 码: 0011 0100
二进制计算应该表示为:
0001 1000 + 0001 0110= 0010 1110
结果差:0011 0100 - 0010 1110=0000 0110
即差 6
3.加一减一
INC source
Increment
source=source+1
source:
A
Rn
direct
@Ri
DPTR
DEC source
Decrement
source=source-1
source:
A
Rn
direct
@Ri
4.乘除法
MUL A,B
无符号乘法,高位存 B,低位存 A
DIV A,B
无符号除法,商存 A,余数存 B
三、逻辑及位移
source:
direct
Rn
@Ri
#data
1.逻辑与
ANL A,source
ANL direct,A/#data
按位相与
2.逻辑或
ORL A,source
ORL direct,A/#data
按位相或
3.逻辑异或
XRL A,source
XRL direct,A/#data
按位相异或
4.清零和取反
CLR A
清零
A 中内容清零,影响 P 标志位
CPL A
取反
Converse Position Logical
A 中内容取反,影响 P 标志位
5.循环位移
RL A
Rotate Left 循环左移
累加器A中最低位向高位移动(不带进位位)
RR A
Rotate Right 循环右移
累加器 A 中最高位向低位移动(不带进位位)
RLC A
Rotate Left through Carry 循环左移
累加器 A 中最低位向高位移动(带进位位)
RRC A
Rotate Right through Carry 循环右移
累加器 A 中最高位向低位移动(带进位位)
带进位位的循环位移
使用之前必须先将 CY 位清零或置位
四、控制转移
跳转指令 用于改变程序的执行顺序,使得程序可以跳到指定的地址继续执行。
跳转指令不保存当前的程序状态,因此在跳转后如果需要返回到原来的执行点,需要手动保存并恢复程序计数器(PC)的值
- 当需要无条件地改变程序执行流程时。
- 实现程序循环时,通过跳转回到循环的开始处。
调用指令 用于调用子程序或中断服务程序,并在调用时自动保存当前的程序计数器(PC)值到堆栈中,以便之后可以返回到调用点。
调用指令通常成对使用,与返回指令(如 RET
或 RETI
)配合,以实现子程序的调用和返回。
- 当需要执行一段可能会重复使用的代码时,可以将其编写为子程序,并通过调用指令执行。
- 在需要中断服务程序时,中断服务程序的入口通过调用指令实现。
程序可以使用标签来指示跳转的目标地址。标签通常用于提高代码的可读性和可维护性,允许程序员通过一个易于理解的名称来引用特定的内存地址。
要标签正确定义且在跳转指令的支持范围内,就可以无限制地使用标签来实现跳转。这为程序的结构化和模块化提供了极大的灵活性。
大多数的跳转指令都可以直接将标签作为跳转目标
1.无条件转移
LJMP addr16
Long Jump
长跳转用于实现长距离的无条件跳转操作
可以转移到 64K 程序储存器的任意位置
PC=addr16
AJMP addr11
Absolute Jump
绝对跳转 只能跳转到PSW寄存器高5位地址范围内的地址
PC=addr11
addr11
是一个11位的地址,表示在8051的64KB的程序存储空间中的位置。
由于8051的地址是按照字节对齐的,所以这个地址实际上是一个16位的地址,其中低11位被用来指定确切的位置
SJMP Rel
Short Jump
实现短距离的无条件跳转操作
Rel
为有符号的 8 位的偏移量
PC=PC+Rel
2.条件转移
累加器 A 判零
JZ rel
Jump if Zero
A 为 0,PC=PC+Rel
JNZ rel
Jump if Not Zero
A 不为 0,PC=PC+Rel
减 1 非零
DJNZ Rn/direct,Rel
Decrement and Jump if Not Zero
首先将指定的寄存器的值减一,
然后检查结果是否为零,
- 如果结果不为零,程序将跳转到指定的标签位置
PC=PC+Rel - 如果结果为零,则不跳转
比较转移
CJNE A/Rn/@Ri,# data,Rel
CJNE A,direct,Rel
Compare and Jump if Not Equal
先进行数值的比较
如果不相等则进行跳转:PC=PC+Rel
3.调用
用于调用一个子程序,并使用堆栈保存当前的程序计数器(PC)的值,
调用指令执行后,堆栈中的值可以被 RET
指令弹出,恢复到调用前的PC值,实现子程序的返回。
绝对调用
ACALL addr11
Absolute Call
addr11
由于8051的程序存储器是按字节寻址的,因此这个地址实际上是一个16位的地址的低11位。
高5位地址由当前的PSW(程序状态字)寄存器中的高5位自动确定
长调用
LCALL addr16
Long Call
LCALL
可以指定完整的16位地址,它提供了更大的灵活性,允许程序员在程序存储器的任何位置调用子程序
4.返回
RET
Return from Subroutine 子程序返回
确保了程序在执行完子程序后能够正确地返回到主程序中的适当位置继续执行
RETI
Return from Interrupt 中断返回
用于从中断 服务程序(ISR)返回
当执行 RETI
指令时,之前在进入中断服务程序时压入堆栈的程序状态字(PSW)和程序计数器(PC)的值会被依次弹出,并加载到相应的寄存器中,使得程序继续从被中断的点执行
5.空操作
NOP
消耗 1 个机器周期
五、位操作
20H~2FH RAM位寻址区
1.位传送
MOV C,bit
C=bit
MOV bit,C
bit=C
可位寻址区 bit 与 CY 位进行数据交换
2.位设置和位清零
CLR C/bit
将 C 或 bit 置 0
SETB C/bit
将 C 或 bit 置 1
3.位运算
ANL C,bit
将 bit 与 CY 相与后给 CY 位
ANL C,/bit
将 bit 取非与 CY 相与后给 CY 位
ORL C,bit
将 bit 与 CY 相或后给 CY 位
ORL C,/bit
将 bit 取非 与 CY 相与后给 CY 位
CPL C/bit
CY/bit 位取反
4.位转移
JB bit,Rel
Jump if Bit is set
如果 bit=1,PC=PC+Rel
JNB bit,Rel
Jump if Not Bit
如果 bit=0,PC=PC+Rel
JBC bit,Rel
Jump if Bit , Clear
如果 bit=1,
程序跳转:PC=PC+Rel ,并将位清零 bit=0
5.判 CY 标志
JC Rel
Jump if Carry
如果 CY=1,PC=PC+Rel
JNC Rel
Jump if No Carry
如果 CY=0,PC=PC+Rel
六、伪指令
帮助组织代码和数据在内存中的布局
用于控制汇编器的行为,而不是实际的机器指令
ORG
定位伪指令
用于设置程序或数据的起始地址。它告诉汇编器程序或数据应该从哪个内存地址开始放置
END
汇编结束伪指令
表示汇编源代码的结束。它用于指示汇编器源文件中不再有程序代码或数据定义
DATA
数据赋值伪指令
标签 Label
用于给程序中的某个位置或常量赋予一个易于识别的名称。标签的使用可以提高程序的可读性和可维护性,使得程序结构更加清晰
地址标签:用于标识程序或数据的内存地址。
变量标签:用于定义程序中使用的变量的地址。
常量标签:用于定义常量值,便于在程序中引用。
作为跳转目标:在跳转指令中使用标签作为跳转目标。
MOV A, # 10H ; 将立即数10H加载到累加器
A JZ END_IF ; 如果A为0,则跳转到标签END_IF``
作为指令的操作数:在指令中直接使用标签,汇编器会自动替换为对应的地址。
MOV A, START ; 将标签START处的数据移动到累加器A